package com.jordi.tetris.model;

import java.util.ArrayList;
import java.util.Collections;

public class Matrix<E> {

	private ArrayList<ArrayList<E>> data;

	public Matrix(E[][] elements) {

		ArrayList<E> column;

		data = new ArrayList<ArrayList<E>>(elements.length);

		for (int i = 0; i < elements.length; i++) {
			column = new ArrayList<E>(elements[0].length);
			for (int j = 0; j < elements[0].length; j++) {
				column.add(elements[i][j]);
			}
			data.add(column);
		}
	}

	public Matrix(int rows, int columns) {

		if (rows <= 0 || columns <= 0)
			throw new IllegalArgumentException();

		ArrayList<E> column;

		data = new ArrayList<ArrayList<E>>(rows);

		for (int i = 0; i < rows; i++) {
			column = new ArrayList<E>(columns);
			for (int j = 0; j < columns; j++) {
				column.add(null);
			}
			data.add(column);
		}
	}

	public Matrix(Matrix<E> matrix) {

		ArrayList<E> column;

		data = new ArrayList<ArrayList<E>>(matrix.getRows());

		for (int i = 0; i < matrix.getRows(); i++) {
			column = new ArrayList<E>(matrix.getColumns());
			for (int j = 0; j < matrix.getColumns(); j++) {
				column.add(matrix.get(i, j));
			}
			data.add(column);
		}
	}

	private void checkValidRow(int row) {
		if (row < 0 || row > getRows())
			throw new IndexOutOfBoundsException("Invalid row: " + row);
	}

	private void checkValidColumn(int column) {
		if (column < 0 || column > getColumns())
			throw new IndexOutOfBoundsException("Invalid column: " + column);
	}

	public void transpose() {

		ArrayList<E> column;

		Matrix<E> maux = new Matrix<E>(this);

		data = new ArrayList<ArrayList<E>>(maux.getColumns());

		for (int i = 0; i < maux.getColumns(); i++) {
			column = new ArrayList<E>(maux.getRows());
			for (int j = maux.getRows() - 1; j >= 0; j--) {
				column.add(maux.get(j, i));
			}
			data.add(column);
		}

		maux = null;
	}

	public void fallRow(int row) {
		for (int i = row; i >= 0; i--) {
			if (i < getRows() - 1)
				Collections.copy(data.get(i + 1), data.get(i));
		}
		
		for (int i=0; i<getColumns(); i++) {
			set(null, 0, i);
		}
	}

	public E get(int row, int column) {
		checkValidRow(row);
		checkValidColumn(column);
		return data.get(row).get(column);
	}

	public ArrayList<E> getRow(int row) {
		checkValidRow(row);
		return data.get(row);
	}

	public ArrayList<E> getColumn(int column) {
		checkValidColumn(column);
		ArrayList<E> col = new ArrayList<E>(getRows());
		for (int i = 0; i < getRows(); i++) {
			col.add(get(i, column));
		}
		return col;
	}

	public void set(E elem, int row, int column) {
		checkValidRow(row);
		checkValidColumn(column);
		data.get(row).set(column, elem);
	}

	public int getRows() {
		return data.size();
	}

	public int getColumns() {
		return data.get(0).size();
	}

	@Override
	public String toString() {
		String s = "\n";
		for (int i = 0; i < getRows(); i++) {
			s += getRow(i).toString() + "\n";
		}
		return s;
	}
}
